package cn.iocoder.yudao.module.written.exam.service.userwrittenexamrecords;

import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import cn.iocoder.yudao.module.member.service.usercommission.UserCommissionService;
import cn.iocoder.yudao.module.member.service.userpointrecords.UserPointRecordsService;
import cn.iocoder.yudao.module.member.service.userrefund.RefundStrategy;
import cn.iocoder.yudao.module.member.service.userrefund.UserRefundService;
import cn.iocoder.yudao.module.member.service.userwithdraw.UserWithdrawService;
import cn.iocoder.yudao.module.pay.service.packageorder.PackageOrderService;
import cn.iocoder.yudao.module.written.exam.controller.admin.member.vo.WrittenExamMemberPageReqVO;
import cn.iocoder.yudao.module.written.exam.controller.admin.member.vo.WrittenExamMemberRespVO;
import cn.iocoder.yudao.module.written.exam.controller.admin.userwrittenexamrecords.vo.UserWrittenExamRecordsPageReqVO;
import cn.iocoder.yudao.module.written.exam.controller.admin.userwrittenexamrecords.vo.UserWrittenExamRecordsRespVO;
import cn.iocoder.yudao.module.written.exam.controller.admin.userwrittenexamrecords.vo.UserWrittenExamRecordsUpdateReqVO;
import cn.iocoder.yudao.module.written.exam.controller.app.userwrittenexamrecords.vo.AppUserWrittenExamRecordsRespVO;
import cn.iocoder.yudao.module.written.exam.controller.admin.userwrittenexamrecords.vo.UserWrittenExamRecordsSaveReqVO;
import cn.iocoder.yudao.module.written.exam.controller.app.userwrittenexamrecordsdetail.vo.AppUserWrittenExamRecordsDetailGroupRespVO;
import cn.iocoder.yudao.module.written.exam.dal.dataobject.userwrittenexamrecords.UserWrittenExamRecordsDO;
import cn.iocoder.yudao.module.written.exam.dal.dataobject.userwrittenexamrecordsdetail.UserWrittenExamRecordsDetailDO;
import cn.iocoder.yudao.module.written.exam.dal.mysql.userwrittenexamrecords.UserWrittenExamRecordsMapper;
import cn.iocoder.yudao.module.written.exam.service.userwrittenexamrecordsdetail.UserWrittenExamRecordsDetailService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;


import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.written.exam.enums.ErrorCodeConstants.USER_WRITTEN_EXAM_RECORDS_NOT_EXISTS;

/**
 * 笔试记录 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class UserWrittenExamRecordsServiceImpl implements UserWrittenExamRecordsService {

    @Resource
    private UserWrittenExamRecordsMapper userWrittenExamRecordsMapper;
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private MemberUserService memberUserService;
    @Resource
    private UserCommissionService userCommissionService;
    @Resource
    private UserWithdrawService userWithdrawService;
    @Resource
    private UserRefundService userRefundService;
    @Resource
    private PackageOrderService packageOrderService;
    @Resource
    private RefundStrategy refundStrategy;
    @Resource
    private UserPointRecordsService userPointRecordsService;

    private UserWrittenExamRecordsDetailService getUserWrittenExamRecordsDetailService() {
        return applicationContext.getBean(UserWrittenExamRecordsDetailService.class);
    }

    @Override
    public Long createUserWrittenExamRecords(UserWrittenExamRecordsSaveReqVO createReqVO) {
        // 插入
        UserWrittenExamRecordsDO userWrittenExamRecords = BeanUtils.toBean(createReqVO, UserWrittenExamRecordsDO.class);
        userWrittenExamRecordsMapper.insert(userWrittenExamRecords);
        // 返回
        return userWrittenExamRecords.getId();
    }

    @Override
    public void updateUserWrittenExamRecords(UserWrittenExamRecordsUpdateReqVO updateReqVO) {
        // 校验存在
        validateUserWrittenExamRecordsExists(updateReqVO.getId());
        // 更新
        UserWrittenExamRecordsDO updateObj = BeanUtils.toBean(updateReqVO, UserWrittenExamRecordsDO.class);
        userWrittenExamRecordsMapper.updateById(updateObj);
    }

    @Override
    public void deleteUserWrittenExamRecords(Long id) {
        // 校验存在
        validateUserWrittenExamRecordsExists(id);
        // 删除
        userWrittenExamRecordsMapper.deleteById(id);
    }

    private void validateUserWrittenExamRecordsExists(Long id) {
        if (userWrittenExamRecordsMapper.selectById(id) == null) {
            throw exception(USER_WRITTEN_EXAM_RECORDS_NOT_EXISTS);
        }
    }

    @Override
    public UserWrittenExamRecordsDO getUserWrittenExamRecords(Long id) {
        UserWrittenExamRecordsDO userWrittenExamRecordsDO = userWrittenExamRecordsMapper.selectById(id);
        if (Objects.isNull(userWrittenExamRecordsDO)) {
            throw exception(USER_WRITTEN_EXAM_RECORDS_NOT_EXISTS);
        }
        return userWrittenExamRecordsDO;
    }

    @Override
    public AppUserWrittenExamRecordsRespVO getUserWrittenExamRecordsForApp(Long id) {
        UserWrittenExamRecordsDO userWrittenExamRecordsDO = userWrittenExamRecordsMapper.selectById(id);
        if (Objects.isNull(userWrittenExamRecordsDO)) {
            throw exception(USER_WRITTEN_EXAM_RECORDS_NOT_EXISTS);
        }
        UserWrittenExamRecordsDetailService userWrittenExamRecordsDetailService = getUserWrittenExamRecordsDetailService();
        List<UserWrittenExamRecordsDetailDO> userWrittenExamRecordsDetailDOList = userWrittenExamRecordsDetailService.getUserWrittenExamRecordsDetailByRecordsId(userWrittenExamRecordsDO.getId());
        Integer questionCount = 0;
        Integer consumedPoints = 0;
        if (!CollectionUtils.isEmpty(userWrittenExamRecordsDetailDOList)) {
            questionCount = userWrittenExamRecordsDetailDOList.size();
            for (UserWrittenExamRecordsDetailDO userWrittenExamRecordsDetailDO : userWrittenExamRecordsDetailDOList) {
                consumedPoints += userWrittenExamRecordsDetailDO.getConsumedPoints();
            }
        }
        AppUserWrittenExamRecordsRespVO appUserWrittenExamRecordsRespVO = BeanUtils.toBean(userWrittenExamRecordsDO, AppUserWrittenExamRecordsRespVO.class);
        appUserWrittenExamRecordsRespVO.setQuestionCount(questionCount);
        appUserWrittenExamRecordsRespVO.setConsumedPoints(consumedPoints);
        return appUserWrittenExamRecordsRespVO;
    }

    @Override
    public UserWrittenExamRecordsDO getUserWrittenExamRecordsByConversationId(String conversationId) {
        LambdaQueryWrapper<UserWrittenExamRecordsDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserWrittenExamRecordsDO::getConversationId, conversationId);
        return userWrittenExamRecordsMapper.selectOne(lambdaQueryWrapper);
    }

    @Override
    public PageResult<UserWrittenExamRecordsRespVO> getUserWrittenExamRecordsPage(UserWrittenExamRecordsPageReqVO pageReqVO) {
        UserWrittenExamRecordsDetailService userWrittenExamRecordsDetailService = getUserWrittenExamRecordsDetailService();
        PageResult<UserWrittenExamRecordsDO> pageResult = userWrittenExamRecordsMapper.selectPage(pageReqVO);
        List<UserWrittenExamRecordsDO> userWrittenExamRecordsDOList = pageResult.getList();
        List<UserWrittenExamRecordsRespVO> userWrittenExamRecordsRespVOList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(userWrittenExamRecordsDOList)) {
            List<Long> recordsIds = userWrittenExamRecordsDOList.stream().map(UserWrittenExamRecordsDO::getId)
                    .collect(Collectors.toList());
            Map<Long, AppUserWrittenExamRecordsDetailGroupRespVO> map = userWrittenExamRecordsDetailService.groupByRecordsId(recordsIds);
            userWrittenExamRecordsRespVOList = userWrittenExamRecordsDOList.stream().map(userWrittenExamRecordsDO -> {
                UserWrittenExamRecordsRespVO userWrittenExamRecordsRespVO = BeanUtils.toBean(userWrittenExamRecordsDO, UserWrittenExamRecordsRespVO.class);
                userWrittenExamRecordsRespVO.setQuestionCount(0);
                userWrittenExamRecordsRespVO.setConsumedPoints(0);
                AppUserWrittenExamRecordsDetailGroupRespVO appUserWrittenExamRecordsDetailGroupRespVO = map.get(userWrittenExamRecordsDO.getId());
                if (Objects.nonNull(appUserWrittenExamRecordsDetailGroupRespVO)) {
                    userWrittenExamRecordsRespVO.setQuestionCount(appUserWrittenExamRecordsDetailGroupRespVO.getQuestionCount());
                    userWrittenExamRecordsRespVO.setConsumedPoints(appUserWrittenExamRecordsDetailGroupRespVO.getConsumedPoints());
                }
                if (Objects.isNull(userWrittenExamRecordsDO.getEndTime())) {
                    UserWrittenExamRecordsDetailDO endUserWrittenExamRecordsDetail = userWrittenExamRecordsDetailService.getEndUserWrittenExamRecordsDetail(userWrittenExamRecordsDO.getId());
                    if (Objects.nonNull(endUserWrittenExamRecordsDetail)) {
                        userWrittenExamRecordsRespVO.setEndTime(endUserWrittenExamRecordsDetail.getCreateTime());
                    }
                }
                return userWrittenExamRecordsRespVO;
            }).collect(Collectors.toList());
        }
        PageResult<UserWrittenExamRecordsRespVO> pageResultResp = new PageResult<>();
        pageResultResp.setTotal(pageResult.getTotal());
        pageResultResp.setList(userWrittenExamRecordsRespVOList);

        return pageResultResp;
    }

    @Override
    public PageResult<AppUserWrittenExamRecordsRespVO> getUserWrittenExamRecordsPageForApp(UserWrittenExamRecordsPageReqVO pageReqVO) {
        UserWrittenExamRecordsDetailService userWrittenExamRecordsDetailService = getUserWrittenExamRecordsDetailService();
        PageResult<UserWrittenExamRecordsDO> pageResult = userWrittenExamRecordsMapper.selectPage(pageReqVO);
        List<UserWrittenExamRecordsDO> userWrittenExamRecordsDOList = pageResult.getList();
        List<AppUserWrittenExamRecordsRespVO> appUserWrittenExamRecordsRespVOList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(userWrittenExamRecordsDOList)) {
            List<Long> recordsIds = userWrittenExamRecordsDOList.stream().map(UserWrittenExamRecordsDO::getId)
                    .collect(Collectors.toList());
            Map<Long, AppUserWrittenExamRecordsDetailGroupRespVO> map = userWrittenExamRecordsDetailService.groupByRecordsId(recordsIds);
            appUserWrittenExamRecordsRespVOList = userWrittenExamRecordsDOList.stream().map(userWrittenExamRecordsDO -> {
                AppUserWrittenExamRecordsRespVO appUserWrittenExamRecordsRespVO = BeanUtils.toBean(userWrittenExamRecordsDO, AppUserWrittenExamRecordsRespVO.class);
                appUserWrittenExamRecordsRespVO.setQuestionCount(0);
                appUserWrittenExamRecordsRespVO.setConsumedPoints(0);
                AppUserWrittenExamRecordsDetailGroupRespVO appUserWrittenExamRecordsDetailGroupRespVO = map.get(userWrittenExamRecordsDO.getId());
                if (Objects.nonNull(appUserWrittenExamRecordsDetailGroupRespVO)) {
                    appUserWrittenExamRecordsRespVO.setQuestionCount(appUserWrittenExamRecordsDetailGroupRespVO.getQuestionCount());
                    appUserWrittenExamRecordsRespVO.setConsumedPoints(appUserWrittenExamRecordsDetailGroupRespVO.getConsumedPoints());
                }
                return appUserWrittenExamRecordsRespVO;
            }).collect(Collectors.toList());
        }
        PageResult<AppUserWrittenExamRecordsRespVO> pageResultResp = new PageResult<>();
        pageResultResp.setTotal(pageResult.getTotal());
        pageResultResp.setList(appUserWrittenExamRecordsRespVOList);

        return pageResultResp;
    }

    private WrittenExamMemberRespVO getWrittenExamMemberRespVO(Long userId) {
        WrittenExamMemberRespVO writtenExamMemberRespVO = new WrittenExamMemberRespVO();
        writtenExamMemberRespVO.setUserId(userId);
        MemberUserDO memberUserDO = memberUserService.getUser(userId);
        writtenExamMemberRespVO.setAvatar(memberUserDO.getAvatar());
        writtenExamMemberRespVO.setMobile(memberUserDO.getMobile());
        writtenExamMemberRespVO.setNickname(memberUserDO.getNickname());
        writtenExamMemberRespVO.setStatus(memberUserDO.getStatus());
        writtenExamMemberRespVO.setPoints(memberUserDO.getPoints());
        writtenExamMemberRespVO.setInviteCode(memberUserDO.getInviteCode());
        writtenExamMemberRespVO.setLoginDate(memberUserDO.getLoginDate());
        writtenExamMemberRespVO.setRegTime(memberUserDO.getCreateTime());

        Integer totalCommission = userCommissionService.totalCommissionByUserId(userId);
        writtenExamMemberRespVO.setTotalCommission(totalCommission);
        writtenExamMemberRespVO.setTotalWithdrawSucc(userWithdrawService.totalWithdrawByUserIdAndStatusSucc(userId));
        Integer totalWithdraw = userWithdrawService.totalWithdrawByUserId(userId);
        writtenExamMemberRespVO.setWithdrawAvailable(userWithdrawService.withdrawAvailable(totalCommission - totalWithdraw));
        Integer packageTotalPrice = packageOrderService.totalPrice(userId);
        Integer totalRefund = userRefundService.totalRefund(userId);
        Integer useTotalPoints = userPointRecordsService.useTotalPoints(userId);
        Integer useFee = refundStrategy.getUseFee(useTotalPoints);
        writtenExamMemberRespVO.setRefundAvailable(packageTotalPrice - totalRefund - useFee);
        writtenExamMemberRespVO.setPackageTotalPrice(packageTotalPrice);

        return writtenExamMemberRespVO;
    }

    @Override
    public PageResult<WrittenExamMemberRespVO> getWrittenExamMemberPage(WrittenExamMemberPageReqVO pageReqVO) {
        PageResult<WrittenExamMemberRespVO> pageResult = new PageResult<>();
        List<WrittenExamMemberRespVO> writtenExamMemberRespVOList = new ArrayList<>();
        long total = 0L;
        if (Objects.isNull(pageReqVO.getUserId())
                && StringUtils.isEmpty(pageReqVO.getNickname())
                && StringUtils.isEmpty(pageReqVO.getMobile())
                && StringUtils.isEmpty(pageReqVO.getInviteCode())) {
            Page<UserWrittenExamRecordsDO> page = Page.of(pageReqVO.getPageNo(), pageReqVO.getPageSize());
            Page<WrittenExamMemberRespVO> writtenExamMemberRespVOPage = userWrittenExamRecordsMapper.selectUserIdsPage(page);
            total = writtenExamMemberRespVOPage.getTotal();
            for (WrittenExamMemberRespVO writtenExamMemberRespVO : writtenExamMemberRespVOPage.getRecords()) {
                writtenExamMemberRespVOList.add(getWrittenExamMemberRespVO(writtenExamMemberRespVO.getUserId()));
            }
        } else {
            Long userId = null;
            if (Objects.nonNull(pageReqVO.getUserId())) {
                userId = pageReqVO.getUserId();
            } else if (!StringUtils.isEmpty(pageReqVO.getNickname())) {
                MemberUserPageReqVO memberUserPageReqVO = new MemberUserPageReqVO();
                memberUserPageReqVO.setNickname(pageReqVO.getNickname());
                memberUserPageReqVO.setPageNo(pageReqVO.getPageNo());
                memberUserPageReqVO.setPageSize(pageReqVO.getPageSize());
                PageResult<MemberUserDO> memberUserDOPageResult = memberUserService.getUserPage(memberUserPageReqVO);
                if (!CollectionUtils.isEmpty(memberUserDOPageResult.getList())) {
                    total = memberUserDOPageResult.getTotal();
                    List<MemberUserDO> memberUserDOList = memberUserDOPageResult.getList();
                    for (MemberUserDO memberUserDO : memberUserDOList) {
                        writtenExamMemberRespVOList.add(getWrittenExamMemberRespVO(memberUserDO.getId()));
                    }
                }
            } else if (!StringUtils.isEmpty(pageReqVO.getMobile())) {
                MemberUserDO memberUserDO = memberUserService.getUserByMobile(pageReqVO.getMobile());
                if (Objects.nonNull(memberUserDO)) {
                    userId = memberUserDO.getId();
                }
            } else if (!StringUtils.isEmpty(pageReqVO.getInviteCode())) {
                MemberUserDO memberUserDO = memberUserService.getUserByInviteCode(pageReqVO.getInviteCode());
                if (Objects.nonNull(memberUserDO)) {
                    userId = memberUserDO.getId();
                }
            }
            if (Objects.nonNull(userId)) {
                writtenExamMemberRespVOList.add(getWrittenExamMemberRespVO(userId));
                total = 1L;
            }
        }
        pageResult.setList(writtenExamMemberRespVOList);
        pageResult.setTotal(total);
        return pageResult;
    }

}